#include<unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>
#include <errno.h>
#include <math.h>
//筷子作为mutex
//加锁(lock)后，别人就无法打开，只有当锁没有关闭(unlock)的时候才能访问资源
pthread_mutex_t chopstick[6] ;
void *eat_think(void *arg)
{
    char phi = *(char *)arg;
    int left,right; //左右筷子的编号
    switch (phi){
        case 'A':
            left = 5;
            right = 1;
            break;
        case 'B':
            left = 1;
            right = 2;
            break;
        case 'C':
            left = 2;
            right = 3;
            break;
        case 'D':
            left = 3;
            right = 4;
            break;
        case 'E':
            left = 4;
            right = 5;
            break;
    }
    while (1){
        sleep(); //思考
        //对左手的筷子加锁（阻塞操作）
        pthread_mutex_lock(&chopstick[left]);
        printf("Philosopher %c fetches chopstick %d\n", phi, left);
        /*   pthread_mutex_trylock
         试图加锁（不阻塞操作）
         当互斥锁空闲时将占有该锁；否则立即返回
         当锁已经在使用的时候，返回为EBUSY，而不是挂起等待。
         **/
        if (pthread_mutex_trylock(&chopstick[right]) == EBUSY){
            //如果右边筷子被拿走放下左手的筷子
            pthread_mutex_unlock(&chopstick[left]);
            printf("Philosopher %c release chopstick %d\n", phi, left);
            continue;
        }
        //这里之所以不用对右手的筷子加锁，是因为pthread_mutex_trylock 已经加过锁了
        //pthread_mutex_lock(&chopstick[right]); //拿起右手的筷子，如果想观察死锁，把上一句if注释掉，再把这一句的注释去掉
        printf("Philosopher %c fetches chopstick %d\n", phi, right);
        printf("Philosopher %c is eating.\n",phi);
        sleep(3); //吃饭
        pthread_mutex_unlock(&chopstick[left]); //放下左手的筷子
        printf("Philosopher %c release chopstick %d\n", phi, left);
        pthread_mutex_unlock(&chopstick[right]); //放下左手的筷子
        printf("Philosopher %c release chopstick %d\n", phi, right);
    }
}

//获得线程属性
void getProperty(pthread_attr_t attr){
    int ret;
    //并发级别
    int level;
    ret = pthread_getconcurrency();
    if(0 != ret) {
        printf("error \n");
    } else {
        printf("线程并发级别为: %d\n", level);
    }
    //线程优先级
    int priority;
    ret = pthread_attr_getschedparam(&attr,&priority);
    if(0 != ret) {
        printf("error \n");
    } else {
        printf("线程优先级 : 优先级 %d\n", priority);
    }
    //线程的调度策略
    int policy;
    ret = pthread_attr_getschedpolicy(&attr, &policy);
    if(0 != ret) {
        printf("error\n");
    }
    else {
        if(SCHED_FIFO == policy)
            //先来先服务
            printf("线程调度策略: 先来先服务\n");
        else if(SCHED_RR == policy)
            //时间片轮转
            printf("线程调度策略: 时间片轮转\n");
        else if(SCHED_OTHER == policy)
            //其他
            printf("线程调度策略: 其他\n");
    }
    //线程栈大小
    size_t size;
    ret = pthread_attr_getstacksize(&attr, &size);
    if(0 != ret) {
        printf("error");
    } else {
        printf("线程栈大小: %lu\n", size);
    }
    //线程的作用域
    int scope;
    ret = pthread_attr_getscope(&attr, &scope);
    if(0 != ret) {
        printf("error");
    } else {
//        非绑定的
        if(PTHREAD_SCOPE_PROCESS == scope)
            printf("线程的作用域: PTHREAD_SCOPE_PROCESS\n");
        //绑定的线程  被绑定的线程具有较高的响应速度
        else if(PTHREAD_SCOPE_SYSTEM == scope)
            printf("线程的作用域: PTHREAD_SCOPE_SYSTEM\n");
    }
}

int main(){
    pthread_t A,B,C,D,E; //5个哲学家
    int i;
    //线程的属性集
    pthread_attr_t attr;
    //对线程属性进行初始化
    pthread_attr_init(&attr);
    //获取线程属性
    getProperty(attr);
    for (i = 0; i < 5; i++)
        pthread_mutex_init(&chopstick[i],NULL);
    pthread_create(&A,&attr, eat_think, "A");
    pthread_create(&B,&attr, eat_think, "B");
    pthread_create(&C,&attr, eat_think, "C");
    pthread_create(&D,&attr, eat_think, "D");
    pthread_create(&E,&attr, eat_think, "E");
    char c;
    //用户输入q，结束进程
    if (scanf("%c",&c)=='q'){
       pthread_cancel(A);
       pthread_cancel(B);
       pthread_cancel(C);
       pthread_cancel(D);
       pthread_cancel(E);
    }
    return 0;
}